package com.simpou.commons.utils.validation;

import com.simpou.commons.utils.behavior.Validator;
import com.simpou.commons.utils.exception.model.BasicRuleViolation;
import com.simpou.commons.utils.exception.model.RuleViolation;
import com.simpou.commons.utils.string.StringLocales;

import lombok.AllArgsConstructor;
import lombok.Getter;

import java.util.Arrays;
import java.util.List;
import java.util.Locale;


/**
 * Validador de Locale.
 *
 * @author Jonas Pereira
 * @since 2011-06-25
 * @version 2013-05-31
 */
public final class LocaleValidator implements Validator<String> {
    /**
     * Todos locales disponíveis na VM.
     */
    private static final List<Locale> LOCALES = Arrays.asList(Locale.getAvailableLocales());

    /**
     * Não entram na regra geral, mas são válidos.
     */
    private static final List<String> exceptions = Arrays.asList("ja_JP_JP_#u-ca-japanese",
            "sr_ME_#Latn", "sr_BA_#Latn", "sr__#Latn", "sr_RS_#Latn",
            "th_TH_TH_#u-nu-thai");

    /**
     * <p>isValid.</p>
     *
     * @param value Valor.
     * @return Se valor é válido. Valor null é considerado válido.
     */
    public static RuleViolation isValid(final String value) {
        final RuleViolation violation;

        if ((value == null) || value.isEmpty()) {
            violation = null;
        } else if (exceptions.contains(value)) {
            violation = null;
        } else if ((value.length() < 2) || (value.length() > 8)) {
            violation = Violation.INVALID_LENGTH;
        } else if (value.equals("he") || value.equals("id")) {
            //exceções: esses valores são alterados ao gerar o locale
            violation = Violation.EXCEPTION;
        } else {
            RuleViolation violationAux;

            try {
                final Locale locale = StringLocales.getStringAsLocale(value);

                if (LOCALES.contains(locale)) {
                    violationAux = null;
                } else {
                    violationAux = Violation.NOT_FOUND;
                }
            } catch (IllegalArgumentException e) {
                violationAux = new BasicRuleViolation(e);
            }

            violation = violationAux;
        }

        return violation;
    }

    /**
     * @param locale Locale a ser validado.
     */
    @Override
    public RuleViolation validate(final String locale) {
        return isValid(locale);
    }
    @Getter
    @AllArgsConstructor
    public enum Violation implements RuleViolation {
        EXCEPTION("Locale is an exception, there aren't rules to validate it."),
        INVALID_LENGTH("Locale must have between 2 and 8 characters but has."),
        NOT_FOUND("Locale is not in avaiable locales list.");
        
        private String msg;

        @Override
        public String getType() {
            return this.name();
        }
    }
}
